package com.aofeng.hybrid.service;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import com.aofeng.hybrid.orm.AssociationMeta;
import com.aofeng.hybrid.orm.Column;
import com.aofeng.hybrid.orm.DBMeta;
import com.aofeng.hybrid.orm.EntityMeta;

import org.json.JSONArray;
import org.json.JSONObject;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;

/**
 * 实体服务
 * 支持json方式的单实体的增删改
 * 支持任何方式的查询
 * Created by LGY on 2016-06-24.
 */
public class EntityService extends GenericService{

    public  EntityService(Context context) {
        super(context);
    }

    /**
     * 实体服务入口
     * @param json 格式{method:方法, json:{方法参数}}
     * @return
     */
    @Override
    public JSONObject action(JSONObject json) {
        JSONObject result = new JSONObject();
        try {
            result.put("code", 500);
            result.put("data", "不可处理异常。");
            String method = json.getString("method");
            if (method.equals("delete")) {
                int n = delete(json.getString("entity"), json.get("id") + "");
                result.put("code", 200);
                result.put("data", n);
                return result;
            } else if (method.equals("save")) {
                JSONObject row = json.getJSONObject("data");
                save(json.getString("entity"), row);
                result.put("code", 200);
                result.put("data", row);
                return result;
            } else {
                result.put("code", 500);
                result.put("data", "不支持的方法。");
                return result;
            }
        } catch(Exception e) {
            try {
                result.put("code", 500);
                result.put("data", e.getMessage());
                return result;
            } catch (Exception ex) {
                //suck
                return result;
            }
        }
    }

    /**
     * 使用id删除，不支持级联
     * @param entity 实体
     * @param id id
     * @return 影响行数
     * @throws Exception
     */
    public int delete(String entity, String id) throws Exception {
        SQLiteDatabase db = context.openOrCreateDatabase("hybrid.db", Context.MODE_PRIVATE, null);
        try {
            DBMeta dbMeta = DBMeta.getMeta(context);
            //得到表名
            String tableName = dbMeta.entityTableNameMap.get(entity);
            //得到实体元数据
            EntityMeta em  = dbMeta.getEntityMeta(tableName);
            return db.delete(tableName, em.id + "=" + Column.normalizeValue(em.idType, id), new String[]{});
        }finally {
            if(db != null)
                db.close();
        }
    }

    /**
     *更新数据
     * @param entity 实体
     * @param jo json对象
     * @throws Exception
     */
    public void update(SQLiteDatabase db, DBMeta dbMeta, String entity, JSONObject jo) throws Exception {
        //得到表名
        String tableName = dbMeta.entityTableNameMap.get(entity);

        //放入数组，统一处理
        JSONArray rows = new JSONArray();
        rows.put(jo);
        updateEntity(db, dbMeta, tableName, rows);
    }

    /**
     * 更新数据库
     * @param db 数据库
     * @param dbMeta 元数据
     * @param tableName 表名
     * @param rows 行
     * @throws Exception
     */
    private void updateEntity(SQLiteDatabase db, DBMeta dbMeta, String tableName, JSONArray rows) throws Exception {
        EntityMeta em  = dbMeta.getEntityMeta(tableName);

        for(int i = 0; i < rows.length(); i++) {
            JSONObject row = rows.getJSONObject(i);
            String sql = "update " + tableName + " set ";
            String where = " where " + em.id + "=" + Column.normalizeValue(em.idType, row.get(em.id)+"");
            Map<String, Object> links = new HashMap<String, Object>();

            Iterator<String> itr = row.keys();
            while (itr.hasNext()) {
                String key = itr.next();
                Object obj = row.get(key);
                //忽略给出的id值
                if (key.equals(em.id))
                    continue;
                if (obj instanceof JSONArray) {
                    links.put(key, obj);
                } else if (obj instanceof JSONObject) {
                    //this will not happen
                } else {
                    String col = em.attrColMap.get(key);
                    String type = em.attrType.get(key);
                    sql += col + " = ";
                    if (!row.isNull(key)) {
                        //如果是日期
                        if(type.equals("date") || type.equals("time")) {
                            String avalue = obj + "";
                            if(avalue.contains("-") || avalue.contains(":")) {
                                sql += "'" + avalue + "',";
                            } else {
                                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                                sql += "'" + sdf.format(new Date(Long.parseLong(avalue))) + "',";
                            }
                        //非日期
                        } else
                            sql += Column.normalizeValue(type, obj + "") + ",";
                    }
                    else
                        sql += "NULL,";
                }
            }

            sql = sql.substring(0, sql.length()-1) + where;
            db.execSQL(sql);

            //递归处理子集合
            itr = links.keySet().iterator();
            while(itr.hasNext()) {
                String associationKey = itr.next();
                JSONArray children = (JSONArray) links.get(associationKey);
                AssociationMeta am = findAssociation(em.ams, associationKey);
                updateEntity(db, dbMeta, am.slave_table, children);
            }
        }
    }

    /**
     * 保存实体
     * 先存主表，再存子表
     * @param entity 实体
     * @param jo 对象
     * @return 新增记录的id
     * @throws Exception
     */
    public String save(String entity, JSONObject jo) throws Exception{
        SQLiteDatabase db = context.openOrCreateDatabase("hybrid.db", Context.MODE_PRIVATE, null);
        try {
        DBMeta dbMeta = DBMeta.getMeta(context);
        //得到表名
        String tableName = dbMeta.entityTableNameMap.get(entity);

        EntityMeta em = dbMeta.getEntityMeta(tableName);
        if(jo.has(em.id)) {
            update(db, dbMeta, entity, jo);
            return null;
        }
        else {
            //放入数组，统一处理
            JSONArray rows = new JSONArray();
            rows.put(jo);
            Ret ret = new Ret();
            saveEntity(db, dbMeta, tableName, rows, null, null, ret);
            return ret.id;
        }
        }finally {
            if(db != null)
                db.close();
        }
    }

    /**
     * 进行数据保存
     * @param db 数据库
     * @param dbMeta  数据库元数据
     * @param tableName  表名
     * @param rows json数据
     * @param linkCol 关联字段
     * @param linkType 关联类型
     * @param ret 返回值
     * @throws Exception
     */
    private void saveEntity(SQLiteDatabase db, DBMeta dbMeta, String tableName, JSONArray rows, String linkCol, String linkType, Ret ret) throws Exception {
        EntityMeta em  = dbMeta.getEntityMeta(tableName);

        String sql = "insert into " + tableName + "(";
        String value = "";

        //如果有关联，则对关联字段赋值
        if (linkCol != null) {
            sql += linkCol + ",";
            value += Column.normalizeValue(linkType, ret.id) + ",";
        }

        for(int i=0; i< rows.length(); i++) {
            String newId = null;
            String s = sql;
            String v = value;

            //确定id，根据id类型，根据类型确定如何给新纪录id赋值
            if (!em.idType.equals("integer")) {
                newId = UUID.randomUUID().toString();
                s += em.id + ",";
                v += "'" + newId + "',";
            }

            Map<String, Object> links = new HashMap<String, Object>();

            //处理简单字段
            JSONObject row = rows.getJSONObject(i);
            Iterator<String> itr = row.keys();
            while (itr.hasNext()) {
                String key = itr.next();
                Object obj = row.get(key);
                //忽略给出的id值
                if (key.equals(em.id))
                    continue;
                if (obj instanceof JSONArray) {
                    links.put(key, obj);
                } else if (obj instanceof JSONObject) {
                    //this will not happen
                } else {
                    String col = em.attrColMap.get(key);
                    String type = em.attrType.get(key);
                    if (!row.isNull(key)) {
                        s += col + ",";
                        //日期全部用字符串存储， 如果日期字段传入了长型，进行转换后保存
                        if(type.equals("date") || type.equals("time")) {
                            String avalue = obj + "";
                            if(avalue.contains("-") || avalue.contains(":")) {
                                v +="'" + avalue + "',";
                            }
                            else {
                                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                                v += "'" + sdf.format(new Date(Long.parseLong(avalue))) + "',";
                            }
                        } else {
                            v += Column.normalizeValue(type, obj + "") + ",";
                        }
                    }
                }
            }
            s = s.substring(0, s.length()-1) + ") values (" + v.substring(0, v.length()-1) + ")";
            db.execSQL(s);
            if(newId == null) {
                Cursor c = db.rawQuery("SELECT last_insert_rowid()", new String[]{});
                newId = c.getInt(0) + "";
            }

            //递归处理子集合
            itr = links.keySet().iterator();
            while(itr.hasNext()) {
                String associationKey = itr.next();
                JSONArray children = (JSONArray) links.get(associationKey);
                AssociationMeta am = findAssociation(em.ams, associationKey);
                Ret r = new Ret();
                r.id = newId;
                saveEntity(db, dbMeta, am.slave_table, children, am.slave_key, am.type, r);
            }
            //记录返回值
            ret.id = newId;
            //回填id
            if (!em.idType.equals("integer"))
                row.put(em.id, newId);
            else
                row.put(em.id, Integer.parseInt(newId));
        }
    }

    /**
     * 查找关联元数据
     * @param ams 关联元数据
     * @param associationKey 关联键值
     * @return 查找到的元数据
     */
    private AssociationMeta findAssociation(AssociationMeta[] ams, String associationKey) {
        for (AssociationMeta meta : ams) {
            if(meta.linkName.equals(associationKey))
                return meta;
        }
        return null;
    }
}

/**
 * 记录返回参数
 */
class Ret {
    public String id;
}
